package com.xieman.anti.replay.utils;

import com.alibaba.fastjson.JSON;
import lombok.Data;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class MdFiveUtils {

    private static final String SALT =
            DigestUtils.md5DigestAsHex("NARUTO-SECURITY".getBytes(StandardCharsets.UTF_8));
    private static final String EMPTY_JSON = "{}";

    public static String encrypt(String data) {
        return DigestUtils.md5DigestAsHex((SALT + data).getBytes(StandardCharsets.UTF_8));
    }

    public static String digest(DigestWorker worker) {
        return digest(
                worker.nonce, worker.url, worker.timestamp, worker.token, worker.params, worker.arguments);
    }

    public static String digest(
            final String nonce,
            final String url,
            final Long timestamp,
            final String token,
            final Object... arguments) {
        return digest(nonce, url, timestamp, token, null, arguments);
    }

    public static String digest(
            final String nonce,
            final String url,
            final Long timestamp,
            final String token,
            final String params) {

        Assert.notBlank(nonce, "nonce不能为空");
        Assert.notBlank(url, "url不能为空");

        StringBuilder sb = new StringBuilder(SALT + nonce + url);

        if (!Objects.isNull(timestamp)) {
            sb.append(timestamp);
        }

        if (!Objects.isNull(token)) {
            sb.append(token);
        }

        if (StringUtils.isNotBlank(params) && !StringUtils.equals(params, EMPTY_JSON)) {
            sb.append(params);
        }

        return DigestUtils.md5DigestAsHex(sb.toString().getBytes(StandardCharsets.UTF_8));
    }

    private static String argumentsSort(final Object... arguments) {
        if (arguments != null && arguments.length > 0) {
            List<Object> list =
                    Arrays.stream(arguments)
                            .sorted(Comparator.comparing(Object::hashCode))
                            .collect(Collectors.toList());

            char[] chars = JSON.toJSONString(list).toCharArray();
            Arrays.sort(chars);
            return Arrays.toString(chars);
        }

        return "";
    }

    public static DigestWorker builder() {
        return new DigestWorker();
    }

    @Data
    public static class DigestWorker {
        private String nonce;
        private String url;
        private Long timestamp;
        private String token;
        private String params;
        private Object[] arguments;

        public DigestWorker nonce(String nonce) {
            this.nonce = nonce;
            return this;
        }

        public DigestWorker url(String url) {
            this.url = url;
            return this;
        }

        public DigestWorker timestamp(Long timestamp) {
            this.timestamp = timestamp;
            return this;
        }

        public DigestWorker token(String token) {
            this.token = token;
            return this;
        }

        public DigestWorker params(String params) {
            this.params = params;
            return this;
        }

        public DigestWorker arguments(Object... arguments) {
            this.arguments = arguments;
            return this;
        }

        public String execute() {
            return MdFiveUtils.digest(this);
        }
    }
}
